Skip to content

추천 기능 구현 및 모듈 이전으로 인한 수정을 진행합니다.#340

Merged
dongglehada merged 19 commits into
devfrom
feat/#339-recommendation-feature
Jun 11, 2026
Merged

추천 기능 구현 및 모듈 이전으로 인한 수정을 진행합니다.#340
dongglehada merged 19 commits into
devfrom
feat/#339-recommendation-feature

Conversation

@dongglehada

Copy link
Copy Markdown
Member

📌 이슈

✅ 작업 사항

추천 기능 구현

  • 추천 화면 기본 구조 및 Reactor/ViewController 구성
  • 비로그인 상태 UI (ToLoginView) 및 수정하기 버튼 → 캐릭터 설정 화면 이동
  • 헤더 검색/알림 버튼 네비게이션 연결
  • 셀 탭 시 도감 상세 화면으로 이동
  • 북마크 버튼 토글 (추가/삭제) — BookmarkRepository 재사용
  • 북마크 추가/삭제 시 스낵바 표시, 컬렉션 추가 모달, 되돌리기 기능
  • 북마크 UI 즉시 반영 (distinctUntilChanged mapId + bookmarkId 비교)

탭바 개선

  • push 시 탭바 자동 숨김, root 복귀 시 표시 (UINavigationControllerDelegate 활용)
  • 탭바 양옆 투명 영역 배경 뷰 추가

버그 수정

  • AppCoordinator 타입 불일치 수정 (AppCoordinatorAppCoordinatorProtocol)
  • 추천 기능 DTO 이중 래핑 제거
  • MLSDesignSystem SPM 모듈 내 UIImage(named:)DesignSystemAsset.image(named:) 전환 (편집 버튼 아이콘, 경고 아이콘 등 5곳)

의존성 구조 개선

  • LoginExitRouteMLSAppFeatureInterfaceMLSCore로 이동 (피처 예시 앱의 앱 레이어 의존 제거)

앱 업데이트 체크

  • 앱 시작 시 App Store 버전 비교 후 강제/선택 업데이트 얼럿 표시
  • 강제 업데이트: 단일 버튼, 포그라운드 복귀 시 얼럿 재표시
  • 선택 업데이트: "나중에" / "업데이트 하기" 버튼, 7일간 스킵 저장
  • "업데이트 하기" 탭 시 App Store로 이동 (itms-apps://)

피처 예시 앱이 앱 레이어(MLSAppFeatureInterface)를 의존하는 문제를 해결.
LoginExitRoute를 MLSCore로 이동하고 관련 타깃 의존성을 정리.
- BookmarkRepository(MLSBookmarkFeatureInterface)를 사용해 북마크 추가/삭제 처리
- 북마크 토글 후 셀 UI 즉시 반영 (distinctUntilChanged mapId+bookmarkId 비교)
- 북마크 추가/삭제 시 스낵바 표시, 컬렉션 추가 및 되돌리기 지원
- 셀 탭 시 상세 화면(DictionaryDetail)으로 이동
- 예시 앱에 Mock 의존성 및 클로저 주입 추가
BottomTabBarController가 각 탭의 NavigationController delegate로 등록되어
스택 depth를 감지해 자동으로 탭바 표시/숨김 처리.
UIImage(named:) -> DesignSystemAsset.image(named:)로 변경하여
SPM 모듈 번들에서 이미지를 올바르게 로드하도록 수정.
탭바 양옆 투명 영역에 배경 뷰 추가.
앱 시작 시 App Store 버전과 비교하여 강제/선택 업데이트 얼럿 표시.
강제 업데이트는 포그라운드 복귀 시 얼럿 재표시, URL 열기 실패 시에도 재표시.
@dongglehada dongglehada requested a review from pinocchio22 June 10, 2026 05:25
@dongglehada dongglehada self-assigned this Jun 10, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an app update checker feature and integrates bookmarking capabilities (adding, deleting, and undoing bookmarks with snackbar notifications) into the recommendation feature. It also refactors the custom bottom tab bar controller to dynamically hide or show itself based on navigation depth. The review feedback highlights several key areas for improvement: preventing potential memory leaks in the update observer, resolving potential delegate conflicts on the navigation controller, ensuring consistent tab bar transition animations, preventing duplicate API requests from rapid bookmark toggling, and simplifying the reactive UI event binding stream.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +73 to +81
case .force:
showForceUpdateAlert()
forceUpdateObserver = NotificationCenter.default.addObserver(
forName: UIApplication.didBecomeActiveNotification,
object: nil,
queue: .main
) { [weak self] _ in
self?.showForceUpdateAlert()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

NotificationCenter의 블록 기반 addObserver는 반환된 옵저버 토큰을 명시적으로 제거하지 않으면 메모리 누수가 발생할 수 있습니다. AppLauncher가 해제되거나 새로운 옵저버를 등록하기 전에 기존 옵저버를 NotificationCenter.default.removeObserver를 통해 제거해주는 것이 안전합니다.

            case .force:
                showForceUpdateAlert()
                if let existingObserver = forceUpdateObserver {
                    NotificationCenter.default.removeObserver(existingObserver)
                }
                forceUpdateObserver = NotificationCenter.default.addObserver(
                    forName: UIApplication.didBecomeActiveNotification,
                    object: nil,
                    queue: .main
                ) { [weak self] _ in
                    self?.showForceUpdateAlert()
                }

Comment on lines +74 to 82
let nav: UINavigationController
if let existing = $0 as? UINavigationController {
nav = existing
} else {
return UINavigationController(rootViewController: $0)
nav = UINavigationController(rootViewController: $0)
}
nav.delegate = self
return nav
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

UINavigationController의 delegate를 self로 설정하고 있습니다. 만약 개별 탭의 NavigationController에 다른 delegate(예: Coordinator 등)가 설정되면, 이 탭바 숨김/표시 기능이 더 이상 동작하지 않게 됩니다. 이를 방지하기 위해 Custom NavigationController를 사용하거나, Coordinator 패턴에서 탭바의 숨김 상태를 직접 제어하는 방식을 고려해보세요.

Comment on lines +156 to +186
func handleToggleBookmark(mapId: Int) -> Observable<Mutation> {
guard let map = currentState.recommendations.first(where: { $0.mapId == mapId }) else {
return .empty()
}

if let bookmarkId = map.bookmarkId {
return bookmarkRepository.deleteBookmark(bookmarkId: bookmarkId)
.flatMap { _ -> Observable<Mutation> in
.from([
.setLastDeleted(map),
.updateBookmarkId(mapId: mapId, bookmarkId: nil),
.setUIEvent(.deleted(map))
])
}
.catch { _ in .empty() }
} else {
return bookmarkRepository.setBookmark(resourceId: mapId, type: .map)
.flatMap { newBookmarkId -> Observable<Mutation> in
let updated = RecommendationMap(
mapId: map.mapId, score: map.score,
iconUrl: map.iconUrl, nameKr: map.nameKr,
bookmarkId: newBookmarkId
)
return .from([
.updateBookmarkId(mapId: mapId, bookmarkId: newBookmarkId),
.setUIEvent(.added(updated))
])
}
.catch { _ in .empty() }
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

사용자가 북마크 버튼을 빠르게 여러 번 탭할 경우, 이전 요청이 완료되기 전에 동일한 API 요청(추가 또는 삭제)이 중복으로 발생할 수 있습니다. 이를 방지하기 위해 버튼 입력을 throttle 처리하거나, Reactor의 State에 isToggling 상태를 두어 요청이 진행 중일 때는 추가 요청을 무시하도록 처리하는 것이 안전합니다.

@pinocchio22 pinocchio22 added feat 새로운 기능을 추가 fix 버그 수정, 잔잔바리 수정, 병합 시 충돌 해결 refactor 프로덕션 코드 리팩토링, 파일 삭제, 네이밍 수정 및 폴더링 labels Jun 10, 2026
@pinocchio22

Copy link
Copy Markdown
Contributor

고생하셨습니다!
제미나이 리뷰 한번 확인 부탁드리고 제가 발견한 이슈 몇가지 적어보겠습니다

  1. 도감 상세에서 도감버튼 누르면 도감탭이 아닌 추천으로 이동 → 목적지 인덱스 수정 필요?
  2. 추천에서 수정하기 눌렀을때 기존 데이터 미입력 + 마이페이지 동일
  3. 프로필 이미지 수정 후 탭바 재노출
  4. 프로필 수정시 완료안눌러도 저장되는듯?

@dongglehada

Copy link
Copy Markdown
Member Author

@pinocchio22
말씀주신 내용 및 ai피드백 내용 취사 적용하여 푸시했습니다!

@dongglehada dongglehada merged commit 68625f5 into dev Jun 11, 2026
2 checks passed
@dongglehada dongglehada deleted the feat/#339-recommendation-feature branch June 11, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새로운 기능을 추가 fix 버그 수정, 잔잔바리 수정, 병합 시 충돌 해결 refactor 프로덕션 코드 리팩토링, 파일 삭제, 네이밍 수정 및 폴더링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

추천 기능 완성 및 모듈 마이그레이션 처리를 완료합니다.

2 participants